﻿using System;
using System.Collections.Generic;
using System.Text;

namespace System.ArgumentParser
{

    [Flags]
    public enum ArgumentFlags
    {
        None = 0,
        Required = 1,
        IsSwitch = 2,
        IsUnnamed = 4,
    }

    public class ArgumentDesc
    {
        /// <summary>
        /// 初始化 <see cref="ArgumentDesc"/> 类的新实例.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="flags">The flags.</param>
        /// <param name="alias">The alias.</param>
        /// <param name="defaultValue">The default value.</param>
        public ArgumentDesc(string name, ArgumentFlags flags, char alias, string defaultValue)
        {
            _Name = name;
            _Alias = alias;
            _Flags = flags;
            _Value = defaultValue;
        }

        private readonly string _Name;
        public string Name
        {
            get { return _Name; }
        }

        private readonly char _Alias;
        public char Alias
        {
            get { return _Alias; }
        }

        private ArgumentFlags _Flags;

        public ArgumentFlags Flags
        {
            get { return _Flags; }
        }

        private string _Value;
        public string Value
        {
            get { return _Value; }
            set { _Value = value; }
        }

        public bool IsSwitch
        {
            get { return (_Flags & ArgumentFlags.IsSwitch) != 0; }
        }

        public bool Required
        {
            get { return (_Flags & ArgumentFlags.Required) != 0; }
        }

        public bool IsUnnamed
        {
            get { return (_Flags & ArgumentFlags.IsUnnamed) != 0; }
        }
    }

    public class ArgumentDescCollection : List<ArgumentDesc>
    {
        public ArgumentDesc Add(string name)
        {
            return Add(name, ArgumentFlags.Required, ' ', null);
        }

        public ArgumentDesc Add(string name, ArgumentFlags flags)
        {
            return Add(name, flags, ' ', null);
        }

        public ArgumentDesc Add(string name, ArgumentFlags flags, char alias)
        {
            return Add(name, flags, alias, null);
        }

        public ArgumentDesc Add(string name, ArgumentFlags flags, char alias, string defaultValue)
        {
            ArgumentDesc newItem = new ArgumentDesc(name, flags, alias, defaultValue);

            Add(newItem);

            return newItem;
        }

        public ArgumentDesc this[string name]
        {
            get { return ItemOfName(name); }
        }

        public ArgumentDesc ItemOfName(string name)
        {
            Predicate<ArgumentDesc> match = delegate(ArgumentDesc item)
            {
                return item.Name == name;
            };

            return Find(match);
        }

        public ArgumentDesc ItemOfAlias(char alias)
        {
            Predicate<ArgumentDesc> match = delegate(ArgumentDesc item)
            {
                return item.Alias == alias;
            };

            return Find(match);
        }

        public List<ArgumentDesc> ItemsOfFlag(ArgumentFlags flag)
        {
            Predicate<ArgumentDesc> match = delegate(ArgumentDesc item)
            {
                return (item.Flags & flag) == flag;
            };

            return FindAll(match);
        }
    }

    public static class ArgumentParser
    {
        public static void GetArguments(
            string[] args,
            ArgumentDescCollection argDescs)
        {
            if (args == null || args.Length < 1) throw new ArgumentException("参数个数不够");

            int i = 0;

            List<ArgumentDesc> unnamedArgs = argDescs.ItemsOfFlag(ArgumentFlags.IsUnnamed);

            while (i < args.Length && i < unnamedArgs.Count)
            {
                if (args[i][0] == '-') break;

                string argValue = args[i];

                unnamedArgs[i].Value = argValue;

                i++;
            }

            while (i < args.Length)
            {
                string arg = args[i];

                if (arg.Length < 2) throw new ArgumentException(string.Format("无效的参数名称 {0}", arg));

                if (arg[0] != '-') throw new ArgumentException(string.Format("无效的参数名称 {0}", arg));

                ArgumentDesc desc = null;

                if (arg[1] == '-')
                {
                    string argName = arg.Substring(2);

                    desc = argDescs.ItemOfName(argName);
                }
                else
                {
                    if (arg.Length == 3)
                    {
                        char alias = arg[2];
                        desc = argDescs.ItemOfAlias(alias);
                    }
                }

                if (desc == null) throw new ArgumentException(string.Format("无效的参数名称 {0}", arg));

                if (desc.IsSwitch)
                {
                    desc.Value = string.Empty;
                }
                else
                {
                    i++;

                    if (i >= args.Length) throw new ArgumentException(string.Format("未指定参数 {0} 的值", desc.Name));

                    string argValue = args[i];

                    desc.Value = argValue;
                }

                i++;
            } // while

            foreach (ArgumentDesc item in argDescs)
            {
                if (item.Required && item.Value == null)
                    throw new ArgumentException(string.Format("未指定必须的参数 {0}", item.Name));
            }
        }
    }
}
